#pragma once

#include "qconf.h"

namespace qio {

class EventLoop;

class FdChanCallbacks;

class FdChan final {
  friend class FdChanCallbacks;

 public:
  enum FdEvent {
    DISABLE = 0,
    READABLE = 1,
    WRITEABLE = 2,
  };

  using OnReadWriteCallback = std::function<void(FdChan *, Fd, int)>;
  using OnErrorCallback = std::function<void(FdChan *, int, const char *)>;
  using OnClosedCallback = std::function<void(FdChan *)>;

 public:
  ~FdChan() QIO_NOEXCEPT;

  FdChan(EventLoop *loop, Fd fd) QIO_NOEXCEPT;

  DISABLE_CPY_MOV(FdChan)

  void Start() QIO_NOEXCEPT;

  void Close() QIO_NOEXCEPT;

  inline Fd GetFd() const QIO_NOEXCEPT { return fd_; }

  inline bool IsWriteable() const QIO_NOEXCEPT {
    return (events_ & WRITEABLE) != 0;
  }

  inline bool IsReadable() const QIO_NOEXCEPT {
    return (events_ & READABLE) != 0;
  }

  void EnableWrite() QIO_NOEXCEPT;

  void EnableRead() QIO_NOEXCEPT;

  void EnableReadWrite() QIO_NOEXCEPT;

  void DisableWrite() QIO_NOEXCEPT;

  void DisableRead() QIO_NOEXCEPT;

  void DisableReadWrite() QIO_NOEXCEPT;

  void UpdateEvents() QIO_NOEXCEPT;

  inline void SetOnReadWriteCallback(OnReadWriteCallback &&cb) QIO_NOEXCEPT {
    rw_cb_ = std::forward<OnReadWriteCallback>(cb);
  }

  inline void SetOnClosedCallback(OnClosedCallback &&cb) QIO_NOEXCEPT {
    closed_cb_ = std::forward<OnClosedCallback>(cb);
  }

  inline void SetOnErrorCallback(OnErrorCallback &&cb) QIO_NOEXCEPT {
    error_cb_ = std::forward<OnErrorCallback>(cb);
  }

 private:
  EventLoop *loop_;
  uv_poll_t *poll_;
  int events_;
  Fd fd_;
  OnReadWriteCallback rw_cb_;
  OnClosedCallback closed_cb_;
  OnErrorCallback error_cb_;
};

}  // namespace qio
